/**
 * 微信支付工具模块
 */
const crypto = require('crypto');
const axios = require('axios');
const xml2js = require('xml2js');
const config = require('../config/env');
const wxConfig = require('../config/wx');

// 微信支付配置
const wxpayConfig = {
  appid: wxConfig.miniapp.appId,
  mchid: wxConfig.payment.mchId || config.wxpay.mchId,
  apiKey: wxConfig.payment.apiKey || config.wxpay.apiKey,
  notifyUrl: wxConfig.payment.notifyUrl || config.wxpay.notifyUrl,
  unifiedOrderUrl: 'https://api.mch.weixin.qq.com/pay/unifiedorder'
};

/**
 * 生成随机字符串
 * @returns {string} 随机字符串
 */
function generateNonceStr() {
  return Math.random().toString(36).substr(2, 15);
}

/**
 * 生成签名
 * @param {Object} params - 签名参数
 * @returns {string} 签名
 */
function generateSign(params) {
  console.log('[微信支付] 开始生成签名，参数：', JSON.stringify(params));
  
  // 1. 过滤空值和签名字段
  const filteredParams = {};
  for (const key in params) {
    if (key !== 'sign' && params[key] !== undefined && params[key] !== null && params[key] !== '') {
      filteredParams[key] = params[key];
    }
  }
  
  // 2. 按字典序排序参数
  const keys = Object.keys(filteredParams).sort();
  
  // 3. 拼接字符串
  let stringA = '';
  for (let i = 0; i < keys.length; i++) {
    const key = keys[i];
    stringA += (i === 0 ? '' : '&') + `${key}=${filteredParams[key]}`;
  }
  
  // 4. 拼接API密钥
  const stringSignTemp = `${stringA}&key=${wxpayConfig.apiKey}`;
  console.log('[微信支付] 待签名字符串：', stringSignTemp);
  
  // 5. MD5签名并转为大写
  const sign = crypto.createHash('md5').update(stringSignTemp, 'utf8').digest('hex').toUpperCase();
  console.log('[微信支付] 生成的签名：', sign);
  
  return sign;
}

/**
 * 将对象转为XML
 * @param {Object} obj - 待转换对象
 * @returns {string} XML字符串
 */
function objectToXml(obj) {
  let xml = '<xml>';
  for (let key in obj) {
    if (obj[key] !== undefined && obj[key] !== null && obj[key] !== '') {
      const value = obj[key];
      if (typeof value === 'object') {
        xml += `<${key}>${objectToXml(value)}</${key}>`;
      } else {
        xml += `<${key}>${value}</${key}>`;
      }
    }
  }
  xml += '</xml>';
  return xml;
}

/**
 * 将XML转为对象
 * @param {string} xml - XML字符串
 * @returns {Promise<Object>} 转换后的对象
 */
function xmlToObject(xml) {
  return new Promise((resolve, reject) => {
    xml2js.parseString(xml, { explicitArray: false, ignoreAttrs: true }, (err, result) => {
      if (err) {
        reject(err);
      } else {
        resolve(result.xml);
      }
    });
  });
}

/**
 * 统一下单接口
 * @param {Object} orderData - 订单数据
 * @returns {Promise<Object>} 统一下单结果
 */
async function unifiedOrder(orderData) {
  try {
    // 开发模式下使用模拟数据返回
    if (process.env.NODE_ENV === 'development' && process.env.MOCK_PAYMENT === 'true') {
      console.log('[微信支付] 开发模式，使用模拟支付数据');
      return {
        return_code: 'SUCCESS',
        result_code: 'SUCCESS',
        prepay_id: 'wx' + Date.now(),
        code_url: 'weixin://wxpay/bizpayurl/up?pr=NwY5Mz9&groupid=00'
      };
    }

    // 确保total_fee是整数
    if (!orderData.total_fee || isNaN(parseInt(orderData.total_fee))) {
      throw new Error('缺少必要参数：total_fee，或total_fee不是有效数字');
    }

    // 确保所有必要参数都存在
    if (!orderData.out_trade_no) {
      throw new Error('缺少必要参数：out_trade_no');
    }

    if (!orderData.body) {
      throw new Error('缺少必要参数：body');
    }

    // 构造统一下单参数
    const params = {
      appid: wxpayConfig.appid,
      mch_id: wxpayConfig.mchid,
      nonce_str: generateNonceStr(),
      body: orderData.body,
      out_trade_no: orderData.out_trade_no,
      total_fee: parseInt(orderData.total_fee), // 确保为整数
      spbill_create_ip: orderData.spbill_create_ip || '127.0.0.1',
      notify_url: wxpayConfig.notifyUrl,
      trade_type: orderData.trade_type || 'JSAPI',
      openid: orderData.openid
    };

    // 详细记录关键配置和参数信息用于调试
    console.log('[微信支付] 统一下单完整参数:', {
      ...params,
      apiKey: wxpayConfig.apiKey ? '已设置' : '未设置', // 不泄露实际密钥
    });

    // 生成签名
    params.sign = generateSign(params);
    console.log('[微信支付] 生成签名:', params.sign);

    // 转为XML
    const xmlData = objectToXml(params);
    
    // 请求统一下单接口
    console.log('[微信支付] 发送请求到:', wxpayConfig.unifiedOrderUrl);
    const response = await axios.post(wxpayConfig.unifiedOrderUrl, xmlData, {
      headers: { 'Content-Type': 'text/xml' }
    });

    // 解析返回结果
    const result = await xmlToObject(response.data);
    console.log('[微信支付] 统一下单返回结果:', result);
    
    if (result.return_code === 'FAIL') {
      console.error('[微信支付] 下单失败:', result.return_msg);
    }
    
    return result;
  } catch (error) {
    console.error('[微信支付] 统一下单请求失败:', error);
    throw error;
  }
}

/**
 * 生成小程序支付参数
 * @param {string} prepayId - 预支付ID
 * @returns {Object} 小程序支付参数
 */
function getPayParams(prepayId) {
  const params = {
    appId: wxpayConfig.appid,
    timeStamp: Math.floor(Date.now() / 1000).toString(),
    nonceStr: generateNonceStr(),
    package: `prepay_id=${prepayId}`,
    signType: 'MD5'
  };

  // 记录签名前参数
  console.log('[微信支付] 支付参数签名前:', JSON.stringify(params));

  // 生成签名
  params.paySign = generateSign(params);
  console.log('[微信支付] 支付参数最终签名:', params.paySign);

  return params;
}

/**
 * 验证支付结果通知
 * @param {Object} data 支付通知数据
 * @returns {boolean} 验证结果
 */
function verifyPaymentNotify(data) {
  // 1. 获取签名
  const sign = data.sign;
  // 2. 删除签名字段
  delete data.sign;
  
  // 3. 按照字典序排序参数
  const keys = Object.keys(data).sort();
  let stringA = '';
  for (let i = 0; i < keys.length; i++) {
    if (data[keys[i]] !== '') {
      stringA += (i === 0 ? '' : '&') + `${keys[i]}=${data[keys[i]]}`;
    }
  }
  
  // 4. 拼接API密钥
  const stringSignTemp = `${stringA}&key=${wxpayConfig.apiKey}`;
  
  // 5. MD5签名并转为大写
  const calculatedSign = crypto.createHash('md5').update(stringSignTemp, 'utf8').digest('hex').toUpperCase();
  
  // 6. 比较签名
  return calculatedSign === sign;
}

module.exports = {
  unifiedOrder,
  getPayParams,
  verifyPaymentNotify,
  wxpayConfig
}; 